import codetree.CodeTree;
import codetree.CodeTreeOperation;
import codetree.TreeNode;
import experiment.NaturalnessPrediction;
import generate.Generate;
import groum.ConstructGroum;
import groum.Groum;
import groum.GroumNode;
import groum.model.db.Record;
import groum.util.Pair;
import japa.parser.JavaParser;
import japa.parser.ast.expr.MethodCallExpr;
import japa.parser.ast.expr.VariableDeclarationExpr;
import predict.Predict;
import com.google.googlejavaformat.java.*;
import treeview.DisplayTreeView;
import treeview.TreeView;
import util.NameExtractor;
import util.NameItem;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Stack;
import java.util.*;
import java.io.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * This is the raw code handler
 * Construct the pre-context of the hole
 * Created by wangxin on 2017/4/22.
 */
public class RawCodeHandler {
    private boolean isControl = false;
    private List<Double> probabilities = new ArrayList<>();
    private int MaxRec = 1;
    private int addLine = 1;
    private int line = 0;
    private List<Generate> generateList = new ArrayList<>();
    private List<String> jdkList = new ArrayList<>();
    private String space = "";
    private List<List<String>> importInfoList = new ArrayList<>();

    public List<Generate> getGenerateList() {
        return generateList;
    }

    public List<List<String>> getImportInfoList() {
        return importInfoList;
    }

    // Constructor
    public RawCodeHandler() {
        // read jdk class name
        String globalPath = System.getProperty("user.dir");
        globalPath = "/home/x/IdeaProjects/CodeRecommendation";
        //List<String> jdkList = new ArrayList<>();
        try {
            File fileClassNameMap = new File(globalPath + "/Extractor/src/main/java/constructdata/configs/JDKCLASS.txt");
            FileInputStream fileInputStream = new FileInputStream(fileClassNameMap);
            Scanner scanner2 = new Scanner(fileInputStream);
            while (scanner2.hasNextLine()) {
                String line = scanner2.nextLine();
                jdkList.add(line);
            }
            scanner2.close();
            fileInputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            //BufferedReader br = new BufferedReader(new FileReader(new File("/home/inspur/Desktop/maxRec.txt")));
            //String temp = null;
            //while ((temp = br.readLine()) != null) {
            //    MaxRec = Integer.valueOf(temp);
            //}
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public RawCodeHandler(List<String> jdkList, String space) {
        this.jdkList = jdkList;
        this.space = space;
    }


    // Handle the raw code here.
    public List<String> handleRawCode(String rawcode) {
        List<String> result = new ArrayList<>();
        String completecode = rawcode;
        String removeCommentCode = rawcode;
        int holeIndex = removeCommentCode.indexOf("$hole$");
        if (holeIndex >= 0) {
            line = getLine(removeCommentCode);
            String code = rawcode.replace("$hole$", "/*hole*/");
            completecode = code;
        }
        String parsedCode = convertRawCode2ParsedCode(completecode);
        String newParsedCode = parsedCode;
        newParsedCode = newParsedCode.replace("/*hole*/", "true == true/*hole*/");
        CodeTree codeTree = getCodeTree(newParsedCode).get(0);
        if (codeTree == null) {
            codeTree = getCodeTree(parsedCode).get(0);
            if (codeTree == null) {
                return null;
            }
            if (codeTree.getTotalNumber() == 1 && "//hole".equals(codeTree.getRoot().getCompleteMethodDeclaration())) {
                return result;
            }
            List<Object> numbers = getHoleNode(parsedCode);
            int serialNumber = (int) numbers.get(0);
            TreeNode childNode = (TreeNode) numbers.get(1);
            /**get the original prediction*/
            CodeTreeOperation operation = new CodeTreeOperation();
            operation.setSerialNumberofEachNode(codeTree);
            List<String> predictions;
            predictions = getPredictedResult(parsedCode, serialNumber, childNode, codeTree);
            result = predictions;
        } else {
            if (codeTree.getTotalNumber() == 1 && "//hole".equals(codeTree.getRoot().getCompleteMethodDeclaration())) {
                return result;
            }
            codeTree.processConditionHole();
            CodeTreeOperation operation = new CodeTreeOperation();
            operation.setSerialNumberofEachNode(codeTree);
            int serialNumber = 0;
            TreeNode holeNode = codeTree.getHoleNode();
            if (holeNode.getParentNode() != null) {
                isControl = holeNode.getParentNode().isControl();
                if (isControl) {
                    if (holeNode.getSerialNumber() == holeNode.getParentNode().getSerialNumber() + 2) {
                        isControl = false;
                    } else if (holeNode.getSerialNumber() == holeNode.getParentNode().getSerialNumber() + 1) {
                        isControl = false;
                    }
                }
                serialNumber = holeNode.getParentNode().getSerialNumber();
            }
            /**get the original prediction*/
            List<String> predictions;
            predictions = getPredictedResult(newParsedCode, serialNumber, new TreeNode(), codeTree);
            result = predictions;
            for (int i = 0; i < result.size(); i++) {
                result.set(i, result.get(i).replace(";", ""));
            }
        }
        return result;
    }
//    public List<String> handleRawCode(String rawcode) {
//        List<String> result = new ArrayList<>();
//        String completecode = rawcode;
//        String removeCommentCode = rawcode;
//        int holeIndex = removeCommentCode.indexOf("$hole$");
//        if (holeIndex >= 0) {
//            line = getLine(removeCommentCode);
//            String code = rawcode.replace("$hole$", "/*hole*/");
//            completecode = code;
//        }
//        String parsedCode = convertRawCode2ParsedCode(completecode);
//        CodeTree codeTree = getCodeTree(parsedCode).get(0);
//        if (codeTree != null) {
//            if (codeTree.getTotalNumber() == 1 && "//hole".equals(codeTree.getRoot().getCompleteMethodDeclaration())) {
//                return result;
//            }
//            List<Object> numbers = getHoleNode(parsedCode);
//            int serialNumber = (int) numbers.get(0);
//            TreeNode childNode = (TreeNode) numbers.get(1);
//            /**get the original prediction*/
//            CodeTreeOperation operation = new CodeTreeOperation();
//            operation.setSerialNumberofEachNode(codeTree);
//            List<String> predictions;
//            predictions = getPredictedResult(parsedCode, serialNumber, childNode, codeTree);
//            result = predictions;
//        } else {
//            String newParsedCode = parsedCode;
//            // String regex = "(?<control>[a-z]+)(\\s|\n)*(?<condition>\\((\\s|\n)*//hole\n(\\s|\n)*\\))(\\s|\n)*\\{(?<body>([\\s\\S])*)\\}";
////            String regex = "(?<control>[a-z]+)(\\s|\n)*(?<condition>\\((\\s|\n)*/\\*hole\\*/(\\s|\n)*\\))(\\s|\n)*\\{(?<body>([\\s\\S])*)\\}";
////            Pattern p = Pattern.compile(regex);
////            Matcher m = p.matcher(parsedCode);
//            // if (m.find()) {
////                String controlLabel = m.group("control");
////                String thenBlock = m.group("body");
////
////                if (controlLabel.equals("if") || controlLabel.equals("while")) {
////                    newParsedCode = newParsedCode.replace("/*hole*/", "true");
////                } else if (controlLabel.equals("for")) {
////                    newParsedCode = newParsedCode.replace("/*hole*/", ";true;");
////                }
////                newParsedCode = newParsedCode.replace(thenBlock, "\ndouble ddddddd = 2d;\nSystem.out.println(ddddddd);\n" + thenBlock);
//            newParsedCode = newParsedCode.replace("/*hole*/", "true == true/*hole*/");
//            codeTree = getCodeTree(newParsedCode).get(0);
//            if (codeTree == null) {
//                return null;
//            } else {
//                if (codeTree.getTotalNumber() == 1 && "//hole".equals(codeTree.getRoot().getCompleteMethodDeclaration())) {
//                    return result;
//                }
//                //codeTree.processConditionHole(codeTree.getRoot());
//                codeTree.processConditionHole();
//                CodeTreeOperation operation = new CodeTreeOperation();
//                operation.setSerialNumberofEachNode(codeTree);
//                int serialNumber = 0;
//                TreeNode holeNode = codeTree.getHoleNode();
//                if (holeNode.getParentNode() != null) {
//                    isControl = holeNode.getParentNode().isControl();
//                    if (isControl) {
//                        if (holeNode.getSerialNumber() == holeNode.getParentNode().getSerialNumber() + 2) {
//                            isControl = false;
//                        } else if (holeNode.getSerialNumber() == holeNode.getParentNode().getSerialNumber() + 1) {
//                            isControl = false;
//                        }
//                    }
//                    serialNumber = holeNode.getParentNode().getSerialNumber();
//                }
//                /**get the original prediction*/
//                List<String> predictions;
//                predictions = getPredictedResult(newParsedCode, serialNumber, new TreeNode(), codeTree);
//                result = predictions;
//                for (int i = 0; i < result.size(); i++) {
//                    result.set(i, result.get(i).replace(";", ""));
//                }
//            }
//
//            // }else{
//            //     return null;
//            // }
//            // todo
//
//        }
//        /*judge termination*/
//        /*
//        Predict predict = new Predict();
//        predict.setSerialNumberString("0");
//        predict.setChildNode( new TreeNode());
//        String globalPath = this.getClass().getClassLoader().getResource("/").getPath();
//        int index = globalPath.indexOf("/out/");
//        globalPath = globalPath.substring(0, index);
//        String terminationResult = predict.predictTermination(codeTree, globalPath);// pathList.get(0)
//        if(terminationResult != null){
//            result.add(0,terminationResult);
//        }*/
//        return result;
//    }

    //convert raw code to the code that we can parse
    private String convertRawCode2ParsedCode(String rawCode) {
        /**get the serial number of hole node's parent node **/
        int startIndex = 0;
        if (rawCode.contains("package")) {
            startIndex = rawCode.indexOf("package");
        } else if (rawCode.contains("import")) {
            startIndex = rawCode.indexOf("import");
        }
        String parsedCode = rawCode.substring(startIndex, rawCode.length());
        return parsedCode;
    }

    // Scan and complete the brackets
    private String scanAndComplete(String precontext) {
        int length = precontext.length();
        Stack<String> signs = new Stack<>();
        boolean isInQuotation = false;
        for (int i = 0; i < length; i++) {
            char temp = precontext.charAt(i);
            if (temp == '\"' || temp == '\'') {
                isInQuotation = !isInQuotation;
            }
            if (!isInQuotation) {
                if (temp == '{') {
                    signs.push("}");
                } else if (temp == '(') {
                    signs.push(")");
                } else if (temp == '}' || temp == ')') {
                    signs.pop();
                }
            }
        }
        while (signs.size() > 0) {
            precontext = precontext + signs.pop();
        }
        return precontext;
    }

    public List<Object> getHoleNode(String parsedCode) {
        List result = new ArrayList();
//        String globalPath = this.getClass().getClassLoader().getResource("/").getPath();
//        int index = globalPath.indexOf("/out/");
//        globalPath = globalPath.substring(0, index);
        String globalPath = "/home/x/IdeaProjects/CodeRecommendation";
        try {
            Predict predict = new Predict();
            List<CodeTree> codeTreeList = predict.getCodeTree(parsedCode, false, true, globalPath, jdkList, null, null);
            CodeTree codeTree = codeTreeList.get(0);
            CodeTreeOperation operation = new CodeTreeOperation();
            operation.setSerialNumberofEachNode(codeTree);
            TreeNode holeNode = codeTree.getHoleNode();
            if (holeNode.getParentNode() != null) {
                isControl = holeNode.getParentNode().isControl();
                if (isControl) {
                    if (holeNode.getSerialNumber() == holeNode.getParentNode().getSerialNumber() + 2) {
                        isControl = false;
                    } else if (holeNode.getSerialNumber() == holeNode.getParentNode().getSerialNumber() + 1) {
                        isControl = false;
                    }
                }
                result.add(holeNode.getParentNode().getSerialNumber());
                if (holeNode.getChildNodes().size() != 0) {
                    result.add(holeNode.getChildNodes().get(0));
                } else {
                    result.add(null);
                }
                return result;
            } else {
                result.add(0);
                result.add(null);
            }
        } catch (Exception e) {
            result.add(0);
            result.add(null);
            // System.err.println("can not get hole node");
        }
        return result;
    }

    public List<CodeTree> getCodeTree(String content) {
        List<CodeTree> result = new ArrayList<>();
//        String globalPath = this.getClass().getClassLoader().getResource("/").getPath();
//        int index = globalPath.indexOf("/out/");
//        globalPath = globalPath.substring(0, index);
        String globalPath = "/home/x/IdeaProjects/CodeRecommendation";
        try {
            Predict predict = new Predict();
            result = predict.getCodeTree(content, false, true, globalPath, jdkList, null, null);
        } catch (Exception e) {
            result.add(null);
            //System.err.println("can not get code tree");
        }
        return result;
    }

    public List<String> getPredictedResult(String content, int serialNumber, TreeNode childNode, CodeTree codeTree) {
        List<String> result = new ArrayList<>();
        List<Integer> countList = new ArrayList<>();
        long startTime = System.currentTimeMillis();
//        String globalPath = this.getClass().getClassLoader().getResource("/").getPath();
//        int index = globalPath.indexOf("/out/");
//        globalPath = globalPath.substring(0, index);
        String globalPath = "/home/x/IdeaProjects/CodeRecommendation";
        try {
            Predict predict = new Predict();
            predict.setSerialNumberString(Integer.toString(serialNumber));
            predict.setChildNode(childNode);
            List<String> top5Result = predict.predict(codeTree, globalPath);// pathList.get(0)
            //System.out.println(top5Result);
            ConstructGroum constructGroum = new ConstructGroum();
            Groum groum = constructGroum.getTestGroum(0, content, false, jdkList,
                    null,
                    null,
                    true, globalPath,
                    new ArrayList<>(), new ArrayList<>());
            // groum.processConditionHole(groum.getRoot(), new ArrayList<>());
            groum.processConditionHole();
            // System.out.println(top5Result);
            NaturalnessPrediction naturalnessPrediction = new NaturalnessPrediction();
            List<String> newTop5Result = naturalnessPrediction.getNaturalnessPrediction_1(groum, top5Result, CodeRecommendationServlet.map);
            // System.out.println(newTop5Result);
            top5Result = weighting(top5Result, newTop5Result);
            Map<String, List<Pair<GroumNode, Double>>> parameterMap = naturalnessPrediction.parameterMap;
            sortParameter(parameterMap);
            List<String> finalResult = new ArrayList<>();
            result = finalResult;
            for (int i = 0; i < top5Result.size(); i++) {
                finalResult.add(recommendParameter(parameterMap, top5Result.get(i), constructGroum.parameterNodeList));
            }
            top5Result = finalResult;
            result = top5Result;
            //System.out.println(top5Result);
            long endTime = System.currentTimeMillis();
            // System.out.print("total time: ");
            // System.out.println(endTime - startTime + "ms");
        } catch (Exception e) {
            e.printStackTrace();
            result = new ArrayList<>();
        } catch (Error e) {
            e.printStackTrace();
            result = new ArrayList<>();
        }
        return result;
    }


    public List<Integer> sort(List<Double> probabilitiesTemp) {
        List<Integer> indices = new ArrayList<>();
        for (int i = 0; i < probabilitiesTemp.size(); i++) {
            indices.add(i);
        }
        for (int i = 0; i < probabilitiesTemp.size(); i++) {
            for (int j = 0; j < probabilitiesTemp.size() - 1 - i; j++) {
                if (probabilitiesTemp.get(j) < probabilitiesTemp.get(j + 1)) {
                    double temp = probabilitiesTemp.get(j);
                    probabilitiesTemp.set(j, probabilitiesTemp.get(j + 1));
                    probabilitiesTemp.set(j + 1, temp);
                    int index = indices.get(j);
                    indices.set(j, indices.get(j + 1));
                    indices.set(j + 1, index);
                }
            }
        }
        return indices;
    }

    public void normalize(int rec) {
        double sum = 0;
        double ratio = 0;
        for (int i = rec; i < 5; i++) {
            sum += probabilities.get(i);
        }
        for (int i = 0; i < rec; i++) {
            ratio += probabilities.get(i);
        }
        for (int i = rec; i < 5; i++) {
            double probability = (probabilities.get(i) / sum) * (1 - ratio);
            probabilities.set(i, probability);
        }
    }

    public int getLine(String text) {
        int i = 0;
        ByteArrayInputStream inputStream = new ByteArrayInputStream(text.getBytes());
        Scanner scanner = new Scanner(inputStream);
        while (scanner.hasNextLine()) {
            String buff = scanner.nextLine();
            i++;
            if (buff.equals("$hole$")) {
                scanner.close();
                return i;
            }
        }
        scanner.close();
        return -1;
    }

    public String getPreContext(String code) {
        int holeIndex = code.indexOf("$hole$");
        String precode = code.substring(0, holeIndex);
        return scanAndComplete(precode);
    }

    public List<String> weighting(List<String> treeLSTMResult, List<String> finalResult) {
        List<String> list = new ArrayList<>();
        Map<String, String> map1 = new HashMap<>();
        Map<String, String> map2 = new HashMap<>();
        Map<String, Double> map3 = new HashMap<>();
        for (String str : treeLSTMResult) {
            map1.put(str.split(" +")[0], str.split(" +")[1]);
        }
        for (String str : finalResult) {
            map2.put(str.split(" +")[0], str.split(" +")[1]);
        }
        for (String key : map1.keySet()) {
            double prob1 = Double.parseDouble(map1.get(key));
            double prob2 = Double.parseDouble(map2.get(key));
            double prob = 0;
            prob = (0.65 * prob1 + 0.35 * prob2);
            map3.put(key, prob);
        }
        for (String key : map1.keySet()) {
            list.add(key + " " + map3.get(key));
        }
        String temp = null;
        for (int i = 0; i < list.size() - 1; i++) {
            for (int j = 0; j < list.size() - 1 - i; j++) {
                if (Double.parseDouble(list.get(j + 1).split(" +")[1]) > Double.parseDouble(list.get(j).split(" +")[1])) {
                    temp = list.get(j);
                    list.set(j, list.get(j + 1));
                    list.set(j + 1, temp);
                }
            }
        }
        return list;
    }

    public void sortParameter(Map<String, List<Pair<GroumNode, Double>>> parameterMap) {
        for (String key : parameterMap.keySet()) {
            List<Pair<GroumNode, Double>> list = parameterMap.get(key);
            Pair<GroumNode, Double> temp = null;
            for (int i = 0; i < list.size() - 1; i++) {
                for (int j = 0; j < list.size() - 1 - i; j++) {
                    if (list.get(j + 1).b.doubleValue() > list.get(j).b.doubleValue()) {
                        temp = list.get(j);
                        list.set(j, list.get(j + 1));
                        list.set(j + 1, temp);
                    } else if (list.get(j + 1).b.doubleValue() == list.get(j).b.doubleValue()) {
                        if (list.get(j + 1).a.getVariableCount() < list.get(j).a.getVariableCount()) {
                            temp = list.get(j);
                            list.set(j, list.get(j + 1));
                            list.set(j + 1, temp);
                        }
                    }
                }
            }
        }
    }

    public String recommendParameter(Map<String, List<Pair<GroumNode, Double>>> parameterMap, String label, List<GroumNode> parameterNodeList) {
        List<String> importInfo = new ArrayList<>();
        String append = "";
        String prediction = label.split(" +")[0];
        String replace = "";
        if (prediction.contains(".new(")) {
            replace = prediction.replace(".new", " ");
            replace = replace.split(" +")[0];
            prediction = prediction.replaceFirst(replace, "woshireplace");
        }
        String expression = prediction;
        String probability = label.split(" +")[1];
        GroumNode temp = new GroumNode();
        for (int i = 0; i < parameterNodeList.size() - 1; i++) {
            for (int j = 0; j < parameterNodeList.size() - 1 - i; j++) {
                if (parameterNodeList.get(j + 1).getVariableCount() < parameterNodeList.get(j).getVariableCount()) {
                    temp = parameterNodeList.get(j);
                    parameterNodeList.set(j, parameterNodeList.get(j + 1));
                    parameterNodeList.set(j + 1, temp);
                }
            }
        }
        List<String> result = new ArrayList<>();
        String key = label.split(" +")[0];
        if (parameterMap.containsKey(key)) {
            //for(String key: parameterMap.keySet()){
            NameExtractor ne = new NameExtractor();
            ne.init();
            if (ne.isNeedForParameter(key)) {
                NameItem ni = ne.getReceiverParameters(key);
                String[] types = ni.toString().split(" +");
                List<Pair<GroumNode, Double>> list = parameterMap.get(key);
                List<String> allVariables = new ArrayList<>();//used to stor all variables ordered by probability
                for (Pair<GroumNode, Double> pair : list) {
                    if (pair.a.getVariableName() != null && !allVariables.contains(pair.a.getVariableName())) {
                        allVariables.add(pair.a.getVariableName());
                    }
                }
                Map<String, List<String>> parameterNameMap = new HashMap<>();
                /*get the types together with names in parameterMap*/
                for (int i = 0; i < list.size(); i++) {
                    String type = list.get(i).a.getType();
                    String name = list.get(i).a.getVariableName();
                    if (parameterNameMap.containsKey(type)) {
                        if (!parameterNameMap.get(type).contains(name)) {
                            parameterNameMap.get(type).add(name);
                        }
                    } else {
                        List<String> nameList = new ArrayList<>();
                        nameList.add(name);
                        parameterNameMap.put(type, nameList);
                    }
                }
                /*add field and method signature parameter*/
                for (GroumNode node : parameterNodeList) {
                    if (node.getVariableName() != null && !allVariables.contains(node.getVariableName())) {
                        allVariables.add(node.getVariableName());
                        if (parameterNameMap.containsKey(node.getType())) {
                            parameterNameMap.get(node.getType()).add(node.getVariableName());
                        } else {
                            List<String> nameList = new ArrayList<>();
                            nameList.add(node.getVariableName());
                            parameterNameMap.put(node.getType(), nameList);
                        }
                    }
                }
                /*choose the correct variable*/
                List<String> oneAppendNodeParameterList = new ArrayList<>();
                for (int i = 0; i < types.length; i++) {
                    String type = types[i];
                    if (i == 0) {
                        try {
                            boolean flag = false;
                            Class clazz = Thread.currentThread().getContextClassLoader().loadClass(type);
                            Method[] methods = clazz.getMethods();
                            Field[] fields = clazz.getFields();
                            for (int j = 0; j < methods.length; j++) {
                                if (methods[j].toString().contains(prediction)) {
                                    String completeReturnType = methods[j].getReturnType().getCanonicalName();
                                    addImportInfo(importInfo, handleType(completeReturnType));
                                    String returnType = methods[j].getReturnType().getSimpleName();
                                    if (!parameterNameMap.containsKey(completeReturnType)) {
                                        if (!key.contains(".append(") && !returnType.contains("Builder")) {
                                            append = returnType + " " + returnType.toLowerCase().replaceAll("\\[\\]", "") + " = ";
                                        }
                                    } else {
                                        if (parameterNameMap.get(completeReturnType).size() > 0 && !key.contains(".append(") && !returnType.contains("Builder")) {
                                            append = parameterNameMap.get(completeReturnType).get(0) + " = ";
                                        } else if (!key.contains(".append(") && !returnType.contains("Builder")) {
                                            append = returnType + " " + returnType.toLowerCase().replaceAll("\\[\\]", "") + " = ";
                                        }
                                    }
                                    flag = true;
                                    break;
                                }
                            }
                            if (!flag) {
                                for (int j = 0; j < fields.length; j++) {
                                    if (fields[j].toString().contains(prediction)) {
                                        String completeReturnType = fields[j].getType().getCanonicalName();
                                        addImportInfo(importInfo, handleType(completeReturnType));
                                        String returnType = fields[j].getType().getSimpleName();
                                        if (!parameterNameMap.containsKey(completeReturnType)) {
                                            if (!key.contains(".append(") && !returnType.contains("Builder")) {
                                                append = returnType + " " + returnType.toLowerCase().replaceAll("\\[\\]", "") + " = ";
                                            }
                                        } else {
                                            if (parameterNameMap.get(completeReturnType).size() > 0 && !key.contains(".append(") && !returnType.contains("Builder")) {
                                                append = parameterNameMap.get(completeReturnType).get(0) + " = ";
                                            } else if (!key.contains(".append(") && !returnType.contains("Builder")) {
                                                append = returnType + " " + returnType.toLowerCase().replaceAll("\\[\\]", "") + " = ";
                                            }
                                        }
                                        break;
                                    }
                                }
                            }
                        } catch (Exception e) {
                            //todo nothing
                        }
                    }
                    String originalType = type;
                    String[] judge = type.split("\\.");
                    String add = "";
                    int typeIndex = 0;
                    if (judge.length > 1) {
                        type = "";
                        for (int index = judge.length - 1; index > 0; index--) {
                            if (Character.isUpperCase(judge[index].charAt(0)) && Character.isLowerCase(judge[index - 1].charAt(0))) {
                                typeIndex = index;
                                break;
                            } else {
                                add += ".";
                                add += judge[index];
                            }
                        }
                        for (int index = 0; index <= typeIndex; index++) {
                            if (index > 0) {
                                type += ".";
                            }
                            type += judge[index];
                        }
                    }
                    addImportInfo(importInfo, handleType(type));
                    if (type.equals("java.lang.Object") || type.equals("java.lang.Object[]")) {
                        if (allVariables.size() > 0) {
                            //type = handleType(type);
                            originalType = handleType(originalType);
                            prediction = prediction.replaceFirst(originalType, allVariables.get(0) + add);
                            oneAppendNodeParameterList.add(allVariables.get(0));
                            String name = allVariables.get(0);
                            for (String typeKey : parameterNameMap.keySet()) {
                                List<String> nameList = parameterNameMap.get(typeKey);
                                if (nameList.contains(name)) {
                                    nameList.remove(name);
                                    break;
                                }
                            }
                            allVariables.remove(0);
                        } else {
                            //type = handleType(type);
                            originalType = handleType(originalType);
                            String[] strs = originalType.split("\\.");
                            prediction = prediction.replaceFirst(originalType, strs[strs.length - 1]);
                            //prediction = prediction.replaceFirst(originalType, "constant");
                            oneAppendNodeParameterList.add("constant");
                        }
                        continue;
                    }
                    if (parameterNameMap.containsKey(type)) {
                        List<String> nameList = parameterNameMap.get(type);
                        if (nameList.size() > 0) {
                            //type = handleType(type);
                            originalType = handleType(originalType);
                            prediction = prediction.replaceFirst(originalType, nameList.get(0) + add);
                            oneAppendNodeParameterList.add(nameList.get(0));
                            allVariables.remove(nameList.get(0));
                            nameList.remove(0);
                        } else {
                            //type = handleType(type);
                            originalType = handleType(originalType);
                            String[] strs = originalType.split("\\.");
                            prediction = prediction.replaceFirst(originalType, strs[strs.length - 1]);
                            // prediction = prediction.replaceFirst(originalType, "constant");
                            oneAppendNodeParameterList.add("constant");
                        }
                    } else {
                        boolean flag = false;
                        for (String typeKey : parameterNameMap.keySet()) {
                            try {
                                Class clazz = Thread.currentThread().getContextClassLoader().loadClass(type);
                                Class clazz2 = Thread.currentThread().getContextClassLoader().loadClass(typeKey);
                                if (clazz2.isAssignableFrom(clazz) || clazz.isAssignableFrom(clazz2) || judgeRelationshipOfCast(type, typeKey)) {
                                    flag = true;
                                    List<String> nameList = parameterNameMap.get(typeKey);
                                    if (nameList.size() > 0) {
                                        //type = handleType(type);
                                        originalType = handleType(originalType);
                                        prediction = prediction.replaceFirst(originalType, nameList.get(0) + add);
                                        oneAppendNodeParameterList.add(nameList.get(0));
                                        allVariables.remove(nameList.get(0));
                                        nameList.remove(0);
                                    } else {
                                        //type = handleType(type);
                                        originalType = handleType(originalType);
                                        String[] strs = originalType.split("\\.");
                                        prediction = prediction.replaceFirst(originalType, strs[strs.length - 1]);
                                        //prediction = prediction.replaceFirst(originalType, "constant");
                                        oneAppendNodeParameterList.add("constant");
                                    }
                                    break;
                                }
                            } catch (Exception e) {
                                continue;
                            }
                        }
                        if (!flag) {
                            if (i == 0) {
                                type = handleType(type);
                                originalType = handleType(originalType);
                                String[] strs = type.split("\\.");
                                prediction = prediction.replaceFirst(originalType, strs[strs.length - 1] + add);
                                oneAppendNodeParameterList.add(strs[strs.length - 1]);
                            } else {
                                // type = handleType(type);
                                originalType = handleType(originalType);
                                String[] strs = originalType.split("\\.");
                                prediction = prediction.replaceFirst(originalType, strs[strs.length - 1]);
                                //prediction = prediction.replaceFirst(originalType, "constant");
                                oneAppendNodeParameterList.add("constant");
                            }
                        }
                    }
                }
                result = oneAppendNodeParameterList;
            } else {
                result.add("controlordeclarationnoneed");
            }
        } else {
            result.add("controlordeclarationnoneed");
        }
        prediction = prediction.replace("woshireplace", replace);
        prediction = handleSpecialPrediction(prediction, importInfo);
        append = handleAppend(append);
        importInfoList.add(importInfo);
        return append + prediction;
        //return prediction + " " + probability;
    }

    public boolean judgeRelationshipOfCast(String sourceClassName, String objectClassName) {
        if (sourceClassName != null && objectClassName != null) {
            if (CodeRecommendationServlet.castMap.get(sourceClassName + "2" + objectClassName) != null) {
                return true;
            } else if (CodeRecommendationServlet.castMap.get(objectClassName + "2" + sourceClassName) != null) {
                return true;
            } else {
                return false;
            }
        }
        return false;
    }

    public String handleType(String type) {
//        if(type.contains("[]")){
//            String str = "\\[\\]";
//            type = type.replace("[]",str);
//        }
        String s = "\\(";
        String s1 = "\\)";
        String s2 = "\\<";
        String s3 = "\\>";
        String s4 = "\\[";
        String s5 = "\\]";
        type = type.replace("(", s);
        type = type.replace(")", s1);
        type = type.replace("<", s2);
        type = type.replace(">", s3);
        type = type.replace("[", s4);
        type = type.replace("]", s5);
        return type;
    }

    public String handleSpecialPrediction(String prediction, List<String> importInfo) {
        String result = "";
        if (prediction.equals("if") || prediction.equals("while")
                || prediction.equals("catch") || prediction.equals("switch")) {
            result = prediction;
            result += "(){\n" + space + "}";
        } else if (prediction.equals("for")) {
            result += "for(;;){\n" + space + "}";
        } else if (prediction.equals("foreach")) {
            result += "for(:){\n" + space + "}";
        } else if (prediction.equals("elseif")) {
            result = "else if(){\n" + space + "}";
        } else if (prediction.equals("doWhile")) {
            result = "do{\n" + space + "}while();";
        } else if (prediction.equals("case")) {
            result = "case:";
        } else if (prediction.equals("finally") || prediction.equals("default")
                || prediction.equals("else")) {
            result = prediction;
            result += "{\n" + space + "}";
        } else if (prediction.equals("try")) {
            result = prediction;
            result += "{\n" + space + "}";
            result += "catch(Exception e){\n" + space + "}";
            result += "finally{\n" + space + "}";
        } else if (prediction.endsWith(".Declaration")) {
            prediction = prediction.replace(".Declaration", "");
            addImportInfo(importInfo, handleType(prediction));
            String[] strs = prediction.split("\\.");
            prediction = strs[strs.length - 1];
            result = prediction + " " + toLowerCase(prediction) + ";";
        } else if (prediction.endsWith(".Null")) {
            prediction = prediction.replace(".Null", "");
            addImportInfo(importInfo, handleType(prediction));
            String[] strs = prediction.split("\\.");
            prediction = strs[strs.length - 1];
            result = prediction + " " + toLowerCase(prediction) + " = null;";
        } else if (prediction.endsWith(".Constant")) {
            prediction = prediction.replace(".Constant", "");
            addImportInfo(importInfo, handleType(prediction));
            String[] strs = prediction.split("\\.");
            prediction = strs[strs.length - 1];
            result = prediction + " " + toLowerCase(prediction) + " = constant;";
        } else if (prediction.endsWith(".ArrayDeclaration[]")) {
            prediction = prediction.replace(".ArrayDeclaration[]", "");
            addImportInfo(importInfo, handleType(prediction));
            String[] strs = prediction.split("\\.");
            prediction = strs[strs.length - 1];
            result = prediction + "[] " + toLowerCase(prediction) + "Array" + ";";
        } else if (prediction.endsWith(".ArrayDeclaration[][]")) {
            prediction = prediction.replace(".ArrayDeclaration[][]", "");
            addImportInfo(importInfo, handleType(prediction));
            String[] strs = prediction.split("\\.");
            prediction = strs[strs.length - 1];
            result = prediction + "[][] " + toLowerCase(prediction) + "Array" + ";";
        } else if (prediction.endsWith(".ArrayNull[]")) {
            prediction = prediction.replace(".ArrayNull[]", "");
            addImportInfo(importInfo, handleType(prediction));
            String[] strs = prediction.split("\\.");
            prediction = strs[strs.length - 1];
            result = prediction + "[] " + toLowerCase(prediction) + "Array" + " = null;";
        } else if (prediction.endsWith(".ArrayNull[][]")) {
            prediction = prediction.replace(".ArrayNull[][]", "");
            addImportInfo(importInfo, handleType(prediction));
            String[] strs = prediction.split("\\.");
            prediction = strs[strs.length - 1];
            result = prediction + "[][] " + toLowerCase(prediction) + "Array" + " = null;";
        } else if (prediction.endsWith(".ArrayConstant[]")) {
            prediction = prediction.replace(".ArrayConstant[]", "");
            addImportInfo(importInfo, handleType(prediction));
            String[] strs = prediction.split("\\.");
            prediction = strs[strs.length - 1];
            result = prediction + "[] " + toLowerCase(prediction) + "Array" + " = constant;";
        } else if (prediction.endsWith(".ArrayConstant[][]")) {
            prediction = prediction.replace(".ArrayConstant[][]", "");
            addImportInfo(importInfo, handleType(prediction));
            String[] strs = prediction.split("\\.");
            prediction = strs[strs.length - 1];
            result = prediction + "[][] " + toLowerCase(prediction) + "Array" + " = constant;";
        } else if (prediction.endsWith(".ArrayInit[]{}")) {
            prediction = prediction.replace(".ArrayInit[]{}", "");
            addImportInfo(importInfo, handleType(prediction));
            String[] strs = prediction.split("\\.");
            prediction = strs[strs.length - 1];
            result = prediction + "[] " + toLowerCase(prediction) + "Array" + " = {};";
        } else if (prediction.endsWith(".ArrayInit[][]{}")) {
            prediction = prediction.replace(".ArrayInit[][]{}", "");
            addImportInfo(importInfo, handleType(prediction));
            String[] strs = prediction.split("\\.");
            prediction = strs[strs.length - 1];
            result = prediction + "[][] " + toLowerCase(prediction) + "Array" + " = {};";
        } else if (prediction.endsWith(".new[]")) {
            prediction = prediction.replace(".new[]", "");
            addImportInfo(importInfo, handleType(prediction));
            String[] strs = prediction.split("\\.");
            prediction = strs[strs.length - 1];
            result = prediction + "[] " + toLowerCase(prediction) + "Array" + " = new " + prediction + "[size]";
        } else if (prediction.endsWith(".new[][]")) {
            prediction = prediction.replace(".new[][]", "");
            addImportInfo(importInfo, handleType(prediction));
            String[] strs = prediction.split("\\.");
            prediction = strs[strs.length - 1];
            result = prediction + "[][] " + toLowerCase(prediction) + "Array" + " = new " + prediction + "[size][size]";
        } else if (prediction.endsWith(".Cast")) {
            prediction = prediction.replace(".Cast", "");
            addImportInfo(importInfo, handleType(prediction));
            String[] strs = prediction.split("\\.");
            prediction = strs[strs.length - 1];
            result = prediction + " " + toLowerCase(prediction) + ";";
        } else if (prediction.contains(".new(")) {
            prediction = prediction.replace(".new", " ");
            String[] strs = prediction.split(" +");
            prediction = strs[0];
            addImportInfo(importInfo, handleType(prediction));
            String[] types = prediction.split("\\.");
            String type = types[types.length - 1];
            result = type + " " + toLowerCase(type) + " = new " + type + strs[1] + ";";
        } else {
            result = prediction;
            result += ";";
        }
        return result;
    }

    public String handleAppend(String append) {
        String result = "";
        if (append.split(" +").length == 3) {
            if (append.startsWith("short") || append.startsWith("byte") || append.startsWith("int")
                    || append.startsWith("long") || append.startsWith("float") || append.startsWith("double")
                    || append.startsWith("char") || append.startsWith("Short")
                    || append.startsWith("Byte") || append.startsWith("Integer") || append.startsWith("Long")
                    || append.startsWith("Float") || append.startsWith("Double") || append.startsWith("Character")) {
                result = "";
                String str1 = append.split(" +")[0];
                String str2 = append.split(" +")[1] + "_variable";
                if (str2.contains("[]")) {
                    str2 = str2.replace("[]", "");
                    str2 += "Array";
                }
                result = str1 + " " + str2 + " = ";
            } else if (append.startsWith("boolean") || append.startsWith("Boolean") || append.startsWith("void")) {
                result = "";
            } else {
                result = append;
            }
        } else {
            result = append;
        }
        return result;
    }

    public String toLowerCase(String prediction) {
        if (Character.isLowerCase(prediction.charAt(0))) {
            prediction = prediction.toLowerCase() + "_variable";
        } else {
            prediction = prediction.toLowerCase();
        }
        prediction = prediction.replaceAll("\\[\\]", "");
        prediction = prediction.replaceAll("\\\\\\[\\\\\\]", "");
        return prediction;
    }

    public void addImportInfo(List<String> importInfo, String type) {
        if (!importInfo.contains(type) && type.contains(".")) {
            if (!"java.lang.String".equals(type)) {
                type = type.replaceAll("\\[\\]", "");
                type = type.replaceAll("\\\\\\[\\\\\\]", "");
                importInfo.add(type);
            }
        }
    }

}



